from utils import _combine_functions, _quotify_function


def vary_on_view(value_func):
    """
    A view decorator that allows the cache middleware to cache responses on
    a per-request basis, using the result of the value_func to generate the
    response's cache key.

    The argument "value_func" must be a view-like function that accepts the
    same arguments as the view that is being decorated. It must return a value
    to be used in the response's cache key.

    This decorator adds a custom response header, which the cache middleware
    will use when generating the response's cache key.

    If the response has Vary:Cookie set in its headers (it probably will if
    vary_on_view is needed), the cache middleware will ignore the cookie value
    when generating the response's cache key. The actual response is not
    affected, which allows the client to do its own caching as usual.

    """

    value_func = _quotify_function(value_func)

    def decorator(func):

        # Build the decorated view that adds the custom response header.
        def inner(request, *args, **kwargs):
            response = func(request, *args, **kwargs)
            if response.status_code == 200:
                if not response.has_header('X-Vary-On-View'):
                    response['X-Vary-On-View'] = ''
                response['X-Vary-On-View'] += value_func(request, *args, **kwargs)
            return response

        # Attach the value_func to the view for the middlware to use. Support
        # nested usage of this decorator by making it return a combined list.
        if hasattr(func, '_vary_on_view'):
            inner._vary_on_view = _combine_functions(func._vary_on_view, value_func)
        else:
            inner._vary_on_view = value_func

        return inner
    return decorator


@vary_on_view
def vary_on_authentication_status(request, *args, **kwargs):
    """
    All authenticated users share a single cached response.
    All anonymous users share a single cached response.

    """
    return request.user.is_authenticated()


@vary_on_view
def vary_on_staff_status(request, *args, **kwargs):
    """
    All staff members share a single cached response.
    All other users share a single cached response.

    """

    return request.user.is_staff()


@vary_on_view
def vary_on_user_type(request, *args, **kwargs):
    """
    All staff members share a single cached response.
    All regular users share a single cached response.
    All anonymous users share a single cached response.

    """

    return int(request.user.is_authenticated()) + int(request.user.is_staff())


@vary_on_view
def vary_on_user_id(request, *args, **kwargs):
    """
    Authenticated users each have their own cached response.
    All anonymous users share a single cached response.

    Avoids caching individual responses for anonymous users when
    your view gives all anonymous users the same response.
    """

    if request.user.is_authenticated():
        return request.user.id
    else:
        return 0
